package com.itunic.cloud.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.reactive.function.client.WebClient;

/**
 * SpringSecurity 基础配置文件
 *
 * @author Sean
 */
@EnableWebFluxSecurity
@Order(-99)
public class WebFluxSecurityConfig {
    @Bean
    @Order(1)
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {

        http.authorizeExchange()
                //对OPTION请求不做任何验证，直接放行
                .pathMatchers("/auth-center/**", "/oauth/**").permitAll().pathMatchers(HttpMethod.OPTIONS).permitAll()
                .and().csrf().disable().cors().disable()
                //所有请求都交给 权限管理器执行
                .authorizeExchange().anyExchange().access(reactiveAuthorizationManager())
                .and()
                //开启ResourceServer，并且提供缺省token支持（如果授权中心提供jwt token，此处也可以更改为jwt）
                .oauth2ResourceServer(ServerHttpSecurity.OAuth2ResourceServerSpec::opaqueToken);
        return http.build();
    }

    /**
     * 自定义一个反应式授权管理器
     *
     * @return
     */
    @Bean
    public ReactiveAuthorizationManager reactiveAuthorizationManager() {
        return new ReactiveBasicAuthorizeConfigManager();
    }

    /**
     * 将配置文件中的oauth 客户端注入进来。
     */
    @Autowired
    private ReactiveClientRegistrationRepository repository;
    @Autowired
    private WebClient.Builder webClient;

    /**
     * 缺省令牌交换器。
     * 所有与授权中心交互，均在此完成。
     * Spring 默认会有实现，为了满足业务需求，所以采取自定义。
     *
     * @return
     */
    @Bean
    public ReactiveOpaqueTokenIntrospector introspector() {
        return new UserInfoOpaqueTokenIntrospector(repository, webClient);
    }
}
